package com.javabasic.snmp;

/**
 * @Author xiongmin
 * @Description //TODO
 * @Date 2020/4/16 12:00
 * @Version 1.0
 **/
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.Counter64;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

/**
 * 演示：WALK的方式获取值
 *
 * blog http://www.micmiu.com
 *
 * @author Michael
 */
public class SnmpWalk {

    public static final int DEFAULT_VERSION = SnmpConstants.version2c;
    public static final String DEFAULT_PROTOCOL = "udp";
    public static final int DEFAULT_PORT = 161;
    public static final long DEFAULT_TIMEOUT = 3 * 1000L;
    public static final int DEFAULT_RETRY = 3;

    /**
     * 创建对象communityTarget
     *
     * // @param targetAddress
     * @param community
     * // @param version
     * // @param timeOut
     * // @param retry
     * @return CommunityTarget
     */
    public static CommunityTarget createDefault(String ip, String community) {
        Address address = GenericAddress.parse(DEFAULT_PROTOCOL + ":" + ip
                + "/" + DEFAULT_PORT);
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(address);
        target.setVersion(DEFAULT_VERSION);
        target.setTimeout(DEFAULT_TIMEOUT); // milliseconds
        target.setRetries(DEFAULT_RETRY);
        return target;
    }

    /**
     * @param ip
     * @param community
     * @param targetOid
     */
    public static void snmpWalk(String ip, String community, String targetOid) {

        CommunityTarget target = createDefault(ip, community);
        TransportMapping transport = null;
        Snmp snmp = null;
        try {
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            transport.listen();

            PDU pdu = new PDU();
            OID targetOID = new OID(targetOid);
            pdu.add(new VariableBinding(targetOID));

            boolean finished = false;
            System.out.println("----> demo start <----");
            while (!finished) {
                VariableBinding vb = null;
                ResponseEvent respEvent = snmp.getNext(pdu, target);

                PDU response = respEvent.getResponse();

                if (null == response) {
                    System.out.println("responsePDU == null");
                    finished = true;
                    break;
                } else {
                    vb = response.get(0);
                }
                // check finish
                finished = checkWalkFinished(targetOID, pdu, vb);
                if (!finished) {
                    System.out.println("==== walk each vlaue :");
                    System.out.println(vb.getOid() + " = " + vb.getVariable());

                    // Set up the variable binding for the next entry.
                    pdu.setRequestID(new Integer32(0));
                    pdu.set(0, vb);
                } else {
                    System.out.println("SNMP walk OID has finished.");
                    snmp.close();
                }
            }
            System.out.println("----> demo end <----");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("SNMP walk Exception: " + e);
        } finally {
            if (snmp != null) {
                try {
                    snmp.close();
                } catch (IOException ex1) {
                    snmp = null;
                }
            }
        }

    }




    public static void snmpWalkWithResult(String ip, String community, String targetOid,List<Object> results) {

        CommunityTarget target = createDefault(ip, community);
        TransportMapping transport = null;
        Snmp snmp = null;
        try {
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            transport.listen();

            PDU pdu = new PDU();
            OID targetOID = new OID(targetOid);
            pdu.add(new VariableBinding(targetOID));

            boolean finished = false;
            System.out.println("----> demo start <----");
            while (!finished) {
                VariableBinding vb = null;
                ResponseEvent respEvent = snmp.getNext(pdu, target);

                PDU response = respEvent.getResponse();

                if (null == response) {
                    System.out.println("responsePDU == null");
                    finished = true;
                    break;
                } else {
                    vb = response.get(0);
                }
                // check finish
                finished = checkWalkFinished(targetOID, pdu, vb);
                if (!finished) {
                    System.out.println("==== walk each vlaue :");
                    System.out.println(vb.getOid() + " = " + vb.getVariable());
                    results.add(vb.getVariable());
                    // Set up the variable binding for the next entry.
                    pdu.setRequestID(new Integer32(0));
                    pdu.set(0, vb);
                } else {
                    System.out.println("SNMP walk OID has finished.");
                    snmp.close();
                }
            }
            System.out.println("----> demo end <----");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("SNMP walk Exception: " + e);
        } finally {
            if (snmp != null) {
                try {
                    snmp.close();
                } catch (IOException ex1) {
                    snmp = null;
                }
            }
        }

    }

    /**
     * 异步采集信息
     *
     * @param ip
     * @param community
     * @param oid
     */
    public static void snmpAsynWalk(String ip, String community, String oid) {
        final CommunityTarget target = createDefault(ip, community);
        Snmp snmp = null;
        try {
            System.out.println("----> demo start <----");

            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();

            final PDU pdu = new PDU();
            final OID targetOID = new OID(oid);
            final CountDownLatch latch = new CountDownLatch(1);
            pdu.add(new VariableBinding(targetOID));

            ResponseListener listener = new ResponseListener() {
                public void onResponse(ResponseEvent event) {
                    ((Snmp) event.getSource()).cancel(event.getRequest(), this);

                    try {
                        PDU response = event.getResponse();
                        // PDU request = event.getRequest();
                        // System.out.println("[request]:" + request);
                        if (response == null) {
                            System.out.println("[ERROR]: response is null");
                        } else if (response.getErrorStatus() != 0) {
                            System.out.println("[ERROR]: response status"
                                    + response.getErrorStatus() + " Text:"
                                    + response.getErrorStatusText());
                        } else {
                            System.out
                                    .println("Received Walk response value :");
                            VariableBinding vb = response.get(0);

                            boolean finished = checkWalkFinished(targetOID,
                                    pdu, vb);
                            if (!finished) {
                                System.out.println(vb.getOid() + " = "
                                        + vb.getVariable());
                                pdu.setRequestID(new Integer32(0));
                                pdu.set(0, vb);
                                ((Snmp) event.getSource()).getNext(pdu, target,
                                        null, this);
                            } else {
                                System.out
                                        .println("SNMP Asyn walk OID value success !");
                                latch.countDown();
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        latch.countDown();
                    }

                }
            };

            snmp.getNext(pdu, target, null, listener);
            System.out.println("pdu 已发送,等到异步处理结果...");

            boolean wait = latch.await(30, TimeUnit.SECONDS);
            System.out.println("latch.await =:" + wait);
            snmp.close();

            System.out.println("----> demo end <----");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("SNMP Asyn Walk Exception:" + e);
        }

    }


    public static void snmpAsynWalkList(String ip, String community, List<String> oidList) {

        oidList.forEach(oid -> {
            snmpAsynWalk(ip,community,oid);
        });

    }



    /**
     * 1)responsePDU == null<br>
     * 2)responsePDU.getErrorStatus() != 0<br>
     * 3)responsePDU.get(0).getOid() == null<br>
     * 4)responsePDU.get(0).getOid().size() < targetOID.size()<br>
     * 5)targetOID.leftMostCompare(targetOID.size(),responsePDU.get(0).getOid())
     * !=0<br>
     * 6)Null.isExceptionSyntax(responsePDU.get(0).getVariable().getSyntax())<br>
     * 7)responsePDU.get(0).getOid().compareTo(targetOID) <= 0<br>
     *
     * // @param resquestPDU
     * @param targetOID
     * // @param responsePDU
     * @param vb
     * @return
     */
    private static boolean checkWalkFinished(OID targetOID, PDU pdu,
                                             VariableBinding vb) {
        boolean finished = false;
        if (pdu.getErrorStatus() != 0) {
            System.out.println("[true] responsePDU.getErrorStatus() != 0 ");
            System.out.println(pdu.getErrorStatusText());
            finished = true;
        } else if (vb.getOid() == null) {
            System.out.println("[true] vb.getOid() == null");
            finished = true;
        } else if (vb.getOid().size() < targetOID.size()) {
            System.out.println("[true] vb.getOid().size() < targetOID.size()");
            finished = true;
        } else if (targetOID.leftMostCompare(targetOID.size(), vb.getOid()) != 0) {
            System.out.println("[true] targetOID.leftMostCompare() != 0");
            finished = true;
        } else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
            System.out
                    .println("[true] Null.isExceptionSyntax(vb.getVariable().getSyntax())");
            finished = true;
        } else if (vb.getOid().compareTo(targetOID) <= 0) {
            System.out.println("[true] Variable received is not "
                    + "lexicographic successor of requested " + "one:");
            System.out.println(vb.toString() + " <= " + targetOID);
            finished = true;
        }
        return finished;

    }

    /**
     *
     * @param args
     */
//    public static void main(String[] args) {
//        String ip = "192.168.1.115";
//        String community = "public";
//        // 1.3.6.1.2.1.2.2.1.2
////        String targetOid = ".1.3.6.1.2.1.1";
//        String targetOid = ".1.3.6.1.4.1.3375.2.2.10.13.2.1.1";
//        snmpWalk(ip, community, targetOid);
//
//
//        System.out.println("\n---------------ASYN-WALK-------------");
//
//        List<String> oidList = new ArrayList<String>();
//        oidList.add(".1.3.6.1.4.1.3375.2.2.10.13.2.1.1");
//        oidList.add(".1.3.6.1.4.1.3375.2.2.10.13.2.1.2");
//        oidList.add(".1.3.6.1.4.1.3375.2.2.10.13.2.1.3");
//        oidList.add(".1.3.6.1.4.1.3375.2.2.10.13.2.1");
//        oidList.add(".1.3.6.1.4.1.3375.2.2.10.14.2.1");
//        // 异步采集数据
//        snmpAsynWalk(ip, community, ".1.3.6.1.4.1.3375.2.2.10.13.2.1.2");
//
//        System.out.println("\n---------------ASYN-WALK-LIST-OID-------------");
//
//        snmpAsynWalkList(ip, community,oidList);
//    }


//    public static void main(String[] args) {
//        String ip = "192.168.1.111";
//        String community = "public";
//        // 1.3.6.1.2.1.2.2.1.2
////        String targetOid = ".1.3.6.1.2.1.1";
////        String targetOid = ".1.3.6.1.4.1.3375.2.2.10.13.2.1";
//
//        System.out.println("\n---------------NUMBER-------------");
//        // TODO 获取所有partition下的VS的数量
//        String targetOid = ".1.3.6.1.4.1.3375.2.2.10.13.1";
//        snmpWalk(ip, community, targetOid);
//
//
//        System.out.println("\n--------------------------------------------");
//        targetOid = ".1.3.6.1.4.1.3375.2.2.10.13.2";
//        snmpWalk(ip, community, targetOid);
//
//
//        System.out.println("\n---------------ASYN-WALK-------------");
//
//        List<String> oidList = new ArrayList<String>();
//        oidList.add(".1.3.6.1.4.1.3375.2.2.10.13.2.1");
//
//
//        System.out.println("\n---------------ASYN-WALK-LIST-OID-------------");
//
//        // 异步采集数据
////        snmpAsynWalkList(ip, community,oidList);
//    }



    public static void main(String[] args) {
        String ip = "192.168.1.115";
        String community = "public";

        System.out.println("\n---------------NUMBER-------------");

        ArrayList<Object> results = new ArrayList<>();

        // TODO 获取F5设备的风扇信息
//        String targetOid = ".1.3.6.1.4.1.3375.2.1.7.4.2.1.14";
////        snmpWalkWithResult(ip, community, targetOid,results);
////        targetOid = ".1.3.6.1.4.1.3375.2.1.7.4.2.1.13.1.48";
////        snmpWalkWithResult(ip, community, targetOid,results);
////        targetOid = ".1.3.6.1.4.1.3375.2.1.1.2.21.37";
////        snmpWalkWithResult(ip, community, targetOid,results);
////        targetOid = ".1.3.6.1.4.1.3375.2.1.1.2.21.38.0";
////        snmpWalkWithResult(ip, community, targetOid,results);
////        targetOid = ".1.3.6.1.2.1.25.2.2.0";
////        snmpWalkWithResult(ip, community, targetOid,results);

        String targetOid = ".1.3.6.1.4.1.3375.2.1.7.4.2.1.13.1.48";
        SnmpGet.snmpGet(ip, community, targetOid);
        targetOid = ".1.3.6.1.4.1.3375.2.1.7.4.2.1.14.1.48";
        SnmpGet.snmpGet(ip, community, targetOid);
        targetOid = ".1.3.6.1.4.1.3375.2.1.1.2.21.37.0";
        SnmpGet.snmpGet(ip, community, targetOid);
        targetOid = ".1.3.6.1.4.1.3375.2.1.1.2.21.38.0";
        SnmpGet.snmpGet(ip, community, targetOid);
        targetOid = ".1.3.6.1.2.1.25.2.2.0";
        SnmpGet.snmpGet(ip, community, targetOid);


        System.out.println("------------------------------------------------");
        targetOid = ".1.3.6.1.4.1.3375.2.1.7.4.2.1.13";
        snmpWalk(ip, community, targetOid);
        targetOid = ".1.3.6.1.4.1.3375.2.1.7.4.2.1.14";
        snmpWalk(ip, community, targetOid);
        targetOid = ".1.3.6.1.4.1.3375.2.1.1.2.21.37";
        snmpWalk(ip, community, targetOid);
        targetOid = ".1.3.6.1.4.1.3375.2.1.1.2.21.38";
        snmpWalk(ip, community, targetOid);
        targetOid = ".1.3.6.1.2.1.25.2.2";
        snmpWalk(ip, community, targetOid);


        System.out.println("------------------------------------------------");
        targetOid = ".1.3.6.1.4.1.3375.2.2.10.13.1";
        snmpWalk(ip, community, targetOid);

//        // TODO 获取F5设备的风扇索引
//        targetOid = ".1.3.6.1.4.1.3375.2.1.3.2.1.2.1.1";
//        snmpWalk(ip, community, targetOid);
//
//        // TODO 获取F5设备的风扇状态
//        targetOid = ".1.3.6.1.4.1.3375.2.1.3.2.1.2.1.2";
//        snmpWalk(ip, community, targetOid);
//
//        // TODO 获取F5设备的风扇转速
//        targetOid = ".1.3.6.1.4.1.3375.2.1.3.2.1.2.1.3";
//        snmpWalk(ip, community, targetOid);



    }

}